package tokenUtil

import (
	"errors"
	"fmt"
	"time"

	"go-api-template/service"

	"github.com/dgrijalva/jwt-go"
)

// UserStdClaims 自定义结构体
type UserStdClaims struct {
	jwt.StandardClaims
	UserStd
}

// UserStd 用户结构体
type UserStd struct {
	UserId  string
	RoleId  string
	IsAdmin bool
}

// Valid  校验claims载体
func (c UserStdClaims) Valid() (err error) {
	// 校验有效期
	if c.ExpiresAt <= time.Now().Unix() {
		return errors.New("token is expired")
	}
	// 校验appIss
	if !c.VerifyIssuer(service.Conf.App.Token.Issue, true) {
		return errors.New("token's issuer is wrong")
	}
	// 校验是否登录（应该不会触发，未登录不返回token）
	if c.Id == "" {
		return errors.New("invalid front in jwt")
	}
	return
}

// JwtGenerateToken 生成token字符串
func JwtGenerateToken(us UserStd, d time.Duration) (string, error) {
	expireTime := time.Now().Add(d)  // 过期时间
	stdClaims := jwt.StandardClaims{ // 初始化载体
		ExpiresAt: expireTime.Unix(),
		IssuedAt:  time.Now().Unix(),
		Id:        us.UserId,
		Issuer:    service.Conf.App.Token.Issue,
	}

	// 用户claims
	uClaims := UserStdClaims{
		StandardClaims: stdClaims,
		UserStd:        us,
	}

	// 创建接口头
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, uClaims)

	// 加密转字符串
	tokenString, err := token.SignedString([]byte(service.Conf.App.Token.Secret))
	if err != nil {
		panic("jwt 配置错误")
	}
	return tokenString, err
}

// TokenParseClaims token字符串转claims载体
func TokenParseClaims(tokenString string) (uc UserStdClaims, err error) {
	if tokenString == "" {
		return uc, errors.New("token 不能为空")
	}

	// 解析Claims载体
	if _, err = jwt.ParseWithClaims(tokenString, &uc, func(token *jwt.Token) (interface{}, error) {
		// 校验加密方法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("意外的签名方法: %v", token.Header["alg"])
		}
		return []byte(service.Conf.App.Token.Secret), nil
	}); err != nil {
		return
	}
	return
}
